﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace Kurogane.Compiler {

	/// <summary>
	/// 抽象構文木で表すときの、一つのノード
	/// </summary>
	public abstract class Ast {
	}

	/// <summary>
	/// 関数を示すノード
	/// </summary>
	public class Proc : Target {
		public string Name { get; set; }
		public IDictionary<string, string> Parameter { get; set; }
		public Block Block { get; set; }
	}

	/// <summary>
	/// 文の塊を示すノード
	/// </summary>
	public class Block : Target {
		public readonly IList<Sentence> Contents = new List<Sentence>();
	}

	/// <summary>
	/// プログラム中の一文を示すノード
	/// </summary>
	public abstract class Sentence : Ast {
	}

	public class NormalSentence : Sentence {
		public readonly IList<SentenceAtom> Contents = new List<SentenceAtom>();
	}

	/// <summary>
	/// 条件文の全体を示すノード
	/// </summary>
	public class CaseSentence : Sentence {
		public readonly List<WhenAtom> Whens = new List<WhenAtom>();
	}

	/// <summary>
	/// 文の構成要素を示すノード
	/// 読点で区切られる。
	/// </summary>
	public abstract class SentenceAtom : Ast {

	}

	/// <summary>
	/// 条件文の各条件とその実行内容を示すノード
	/// </summary>
	public class WhenAtom : SentenceAtom {
		public ActionAtom Cond { get; private set; }
		public Sentence Action { get; private set; }

		public WhenAtom(ActionAtom cond, Sentence action) {
			this.Cond = cond;
			this.Action = action;
		}
	}

	/// <summary>
	/// 実行可能な文の構成要素
	/// 「AをBする」や「AをBし」のようなものを示す。
	/// </summary>
	public class ActionAtom : SentenceAtom {
		public IDictionary<string, Target> Arguments = new Dictionary<string, Target>();
		public Target Action { get; set; }
	}

	public class AssignmentAtom : SentenceAtom {
		public IDictionary<string, Target> Arguments = new Dictionary<string, Target>();
	}

	/// <summary>
	/// 「Aを」の「A」に当たるようなものを示すノード
	/// </summary>
	public abstract class Target {

	}

	/// <summary>
	/// プログラム中に現れる即値を示すノード
	/// </summary>
	public class LiteralTarget : Target {
		public object Value { get; private set; }
		public LiteralTarget(object value) {
			this.Value = value;
		}
	}

	/// <summary>
	/// プログラム中の変数参照を示すノード
	/// </summary>
	public class ReferenceTarget : Target {
		public string Name { get; private set; }
		public ReferenceTarget(string name) {
			this.Name = name;
		}
	}

	/// <summary>
	/// 式を示すノード
	/// </summary>
	public class ExpressionTarget : Target {

	}

	/// <summary>
	/// 単項演算
	/// </summary>
	public class UnaryOperation : ExpressionTarget {
		public string Operation { get; private set; }
		public Target Target { get; private set; }

		public UnaryOperation(string op, Target target) {
			this.Operation = op;
			this.Target = target;
		}
	}

	/// <summary>
	/// 二項演算
	/// </summary>
	public class BinaryOperation : ExpressionTarget {
		public string Operation { get; private set; }
		public Target Left { get; private set; }
		public Target Right { get; private set; }

		public BinaryOperation(Target left, string op, Target right) {
			this.Operation = op;
			this.Left = left;
			this.Right = right;
		}
	}

}
